local extension = Package:new("touhou_debug", Package.SpecialPack)
local HY = require "packages.touhou_hy.utility.utility"
local U = require "packages.utility.utility"
extension.extensionName = "touhou_hy"

local desc_debug = [[
  ## 调试用模式

  身份全明玩家一号位主公带测试技能开局全部控制

  不要在云端用
]]

local debug_getLogic = function()
    local debug_logic = GameLogic:subclass("debug_logic")

    function debug_logic:run()
        local room = self.room

        if #table.filter(room.players, function(t)
                return t.id > 0
            end) > 1 then
            room.game_finished = true
        end

        room.settings._game.enableFreeAssign = true
        room.settings._game.luckTime = 0
        GameLogic.run(self)
    end

    function debug_logic:assignRoles()
        local room = self.room
        local n = #room.players

        local players = {}

        for i = 1, n do
            local p = table.find(table.except(room.players, players), function(t)
                return t.id > 0
            end)
            if p ~= nil then
                table.insertIfNeed(players, p)
            else
                table.insertIfNeed(players, table.except(room.players, players)[1])
            end
        end

        room.players = players
        local role_table = {
            { "lord" },
            { "lord", "rebel" },
            { "lord", "rebel",    "renegade" },
            { "lord", "loyalist", "rebel",    "renegade" },
            { "lord", "loyalist", "rebel",    "rebel",   "renegade" },
            { "lord", "loyalist", "rebel",    "rebel",   "rebel",   "renegade" },
            { "lord", "loyalist", "loyalist", "rebel",   "rebel",   "rebel",   "renegade" },
            { "lord", "loyalist", "loyalist", "rebel",   "rebel",   "rebel",   "rebel",   "renegade" },
        }

        for i = 1, n do
            local p = room.players[i]
            p.role = role_table[n][i]
            room:broadcastProperty(p, "role")
        end
    end

    function debug_logic:chooseGenerals()
        local room = self.room ---@class Room
        local generalNum = room:getSettings('generalNum')
        local n = room:getSettings('enableDeputy') and 2 or 1
        local lord = room:getLord()
        local lord_generals
        local lord_num = 3

        if not lord then
            return
        end
        room:setCurrent(lord)
        local a1 = #room.general_pile
        local a2 = #room.players * generalNum
        if a1 < a2 then
            room:sendLog {
                type = "#NoEnoughGeneralDraw",
                arg = a1,
                arg2 = a2,
                toast = true,
            }
            room:gameOver("")
        end
        lord_num = math.min(a1 - a2, lord_num)
        local generals = table.connect(room:findGenerals(function(g)
            return table.contains(Fk.lords, g)
        end, lord_num), room:getNGenerals(generalNum))
        lord_generals = room:askToChooseGeneral(lord, { generals = generals, n = n })
        local lord_general, deputy
        if type(lord_generals) == "table" then
            deputy = lord_generals[2]
            lord_general = lord_generals[1]
        else
            lord_general = lord_generals
            lord_generals = { lord_general }
        end
        generals = table.filter(generals, function(g)
            return not table.find(lord_generals, function(lg)
                return Fk.generals[lg].trueName == Fk.generals[g].trueName
            end)
        end)
        room:returnToGeneralPile(generals)

        room:prepareGeneral(lord, lord_general, deputy, true)

        room:askToChooseKingdom({ lord })
        room:broadcastProperty(lord, "kingdom")

        -- 显示技能
        local canAttachSkill = function(player, skillName)
            local skill = Fk.skills[skillName]
            if not skill then
                fk.qCritical("Skill: " .. skillName .. " doesn't exist!")
                return false
            end
            if skill:hasTag(Skill.Lord) and not player.role == "lord" then
                return false
            end

            if skill:hasTag(Skill.AttachedKingdom) and not table.contains(skill:getSkeleton().attached_kingdom, player.kingdom) then
                return false
            end

            return true
        end

        local lord_skills = {}
        for _, s in ipairs(Fk.generals[lord.general].skills) do
            if canAttachSkill(lord, s.name) then
                table.insertIfNeed(lord_skills, s.name)
            end
        end
        for _, sname in ipairs(Fk.generals[lord.general].other_skills) do
            if canAttachSkill(lord, sname) then
                table.insertIfNeed(lord_skills, sname)
            end
        end

        local deputyGeneral = Fk.generals[lord.deputyGeneral]
        if deputyGeneral then
            for _, s in ipairs(deputyGeneral.skills) do
                if canAttachSkill(lord, s.name) then
                    table.insertIfNeed(lord_skills, s.name)
                end
            end
            for _, sname in ipairs(deputyGeneral.other_skills) do
                if canAttachSkill(lord, sname) then
                    table.insertIfNeed(lord_skills, sname)
                end
            end
        end
        for _, skill in ipairs(lord_skills) do
            room:doBroadcastNotify("AddSkill", {
                lord.id,
                skill
            })
        end

        local nonlord = room:getOtherPlayers(lord, true)
        local req = Request:new(nonlord, "AskForGeneral")
        req.timeout = self.room:getSettings('generalTimeout')
        local generals = table.random(room.general_pile, #nonlord * generalNum)
        for i, p in ipairs(nonlord) do
            local arg = table.slice(generals, (i - 1) * generalNum + 1, i * generalNum + 1)
            req:setData(p, { arg, n })
            req:setDefaultReply(p, table.random(arg, n))
        end

        for _, p in ipairs(nonlord) do
            local result = req:getResult(p)
            local general, deputy = result[1], result[2]
            room:findGeneral(general)
            room:findGeneral(deputy)
            room:prepareGeneral(p, general, deputy)
        end

        room:askToChooseKingdom(nonlord)
    end

    return debug_logic
end

local debug_rule = fk.CreateSkill {
    name = "debug_rule",
}
debug_rule:addEffect(fk.GameStart, {
    priority = 999,
    can_refresh = function(self, event, target, player, data)
        return target == player
    end,
    on_refresh = function(self, event, target, player, data)
        local room = target.room
        local lord = room:getLord()
        if lord then
            room:handleAddLoseSkills(lord, "test_rende|cheat|control|damage_maker|change_hero|changeSeat|test_zhijian|showAll|debug_protect|removeProtect", nil, false, true)
            for _, t in ipairs(room:getOtherPlayers(lord)) do
                room:addPlayerMark(t, "mouxushengcontrolled")
                lord:control(t)
                room:setPlayerProperty(t, "role_shown", true)
            end
        end
    end
})
debug_rule:addEffect(fk.AfterPropertyChange, {
    priority = 999,
    can_refresh = function(self, event, target, player, data)
        return target == player.room:getLord() and data.results["generalChange"] ~= nil
    end,
    on_refresh = function(self, event, target, player, data)
        local room = target.room
        local lord = room:getLord()
        if lord then
            room:handleAddLoseSkills(lord, "rende|cheat|control|damage_maker|change_hero|changeSeat|showAll|debug_protect|removeProtect", nil, false, true)
            for _, t in ipairs(room:getOtherPlayers(lord)) do
                room:addPlayerMark(t, "mouxushengcontrolled")
                lord:control(t)
                room:setPlayerProperty(t, "role_shown", true)
            end
        end
    end
})
local changeSeat = fk.CreateSkill {
    name = "changeSeat",
}
changeSeat:addEffect("active", {
    target_num = 2,
    card_num = 0,
    card_filter = Util.FalseFunc,
    target_filter = function(self, player, to_select, selected, selected_cards)
        if #selected == 0 then
            return true
        elseif #selected == 1 then
            return to_select ~= selected[1]
        else
            return false
        end
    end,
    can_use = Util.TrueFunc,
    on_use = function(self, room, cardUseEvent)
        local from = cardUseEvent.tos[1]
        local to = cardUseEvent.tos[2]
        room:swapSeat(from, to)
    end
})
local debug_protect = fk.CreateSkill {
    name = "debug_protect",
}
debug_protect:addEffect(fk.HpChanged, {
    can_refresh = function(self, event, target, player, data)
        return player:hasSkill(self, true, true) and target == player
    end,
    on_refresh = function(self, event, target, player, data)
        local room = player.room
        if player.hp <= 0 then
            room:changeHp(player, 1 - player.hp)
        end
    end
})
debug_protect:addEffect(fk.BeforeMaxHpChanged, {
    can_refresh = function(self, event, target, player, data)
        return player:hasSkill(self, true, true) and target == player
    end,
    on_refresh = function(self, event, target, player, data)
        local room = player.room
        if player.maxHp + data.num <= 0 then
            room:changeMaxHp(player, 1 - player.maxHp - data.num)
        end
    end
})
local removeProtect = fk.CreateSkill {
    name = "removeProtect",
}
removeProtect:addEffect("active", {
    target_num = 0,
    card_num = 0,
    card_filter = Util.FalseFunc,
    target_filter = Util.FalseFunc,
    can_use = function(self, player)
        return player:hasSkill("debug_protect", true, true)
    end,
    on_use = function(self, room, cardUseEvent)
        local player = cardUseEvent.from
        room:handleAddLoseSkills(player, "-debug_protect|-removeProtect|addProtect", nil, false, true)
    end
})
local addProtect = fk.CreateSkill {
    name = "addProtect",
}
addProtect:addEffect("active", {
    target_num = 0,
    card_num = 0,
    card_filter = Util.FalseFunc,
    target_filter = Util.FalseFunc,
    can_use = function(self, player)
        return not player:hasSkill("debug_protect", true, true)
    end,
    on_use = function(self, room, cardUseEvent)
        local player = cardUseEvent.from
        room:handleAddLoseSkills(player, "debug_protect|removeProtect|-addProtect", nil, false, true)
    end
})
local showAll = fk.CreateSkill {
    name = "showAll",
}
showAll:addEffect("visibility", {
    role_visible = function(self, player, target)
        return true
    end,
    card_visible = function(self, player, card)
        return true
    end
})
local debug_mode = fk.CreateGameMode {
    name = "debug_mode",
    minPlayer = 2,
    maxPlayer = 8,
    logic = debug_getLogic,
    rule = "debug_rule",
    main_mode = "role_mode",
    winner_getter = function(self, victim)
        if #Fk:currentRoom().alive_players == 1 then
            return "lord"
        end
        return ""
    end,
}

extension:loadSkillSkels { debug_rule, changeSeat, debug_protect, removeProtect, addProtect, showAll }
extension:addGameMode(debug_mode)

Fk:loadTranslationTable {
    ["debug_mode"] = "调试模式",
    [":debug_mode"] = desc_debug,
    ["changeSeat"] = "换位",
    [":changeSeat"] = "交换两名角色的座次",
    ["debug_protect"] = "保护",
    [":debug_protect"] = "死亡保护",
    ["removeProtect"] = "解保",
    [":removeProtect"] = "解除死亡保护",
    ["addProtect"] = "加保",
    [":addProtect"] = "恢复死亡保护",
    ["showAll"] = "全看",
    [":showAll"] = "看身份和牌",
}
return extension
